import { useRef, useCallback, useEffect } from 'react'

interface CacheEntry<T> {
  data: T
  timestamp: number
  ttl: number
  accessCount: number
  lastAccessed: number
}

interface CacheOptions {
  maxSize?: number
  defaultTTL?: number
  cleanupInterval?: number
}

export function useCache<T>(options: CacheOptions = {}) {
  const {
    maxSize = 100,
    defaultTTL = 5 * 60 * 1000, // 5 minutes
    cleanupInterval = 60 * 1000 // 1 minute
  } = options

  const cache = useRef<Map<string, CacheEntry<T>>>(new Map())
  const cleanupTimer = useRef<number>()

  // Cleanup expired entries
  const cleanup = useCallback(() => {
    const now = Date.now()
    const entries = Array.from(cache.current.entries())
    
    entries.forEach(([key, entry]) => {
      if (now - entry.timestamp > entry.ttl) {
        cache.current.delete(key)
      }
    })

    // If cache is still too large, remove least recently used items
    if (cache.current.size > maxSize) {
      const sortedEntries = entries
        .filter(([key]) => cache.current.has(key)) // Only include non-expired entries
        .sort((a, b) => a[1].lastAccessed - b[1].lastAccessed)
      
      const toRemove = sortedEntries.slice(0, cache.current.size - maxSize)
      toRemove.forEach(([key]) => cache.current.delete(key))
    }
  }, [maxSize])

  // Set up cleanup interval
  useEffect(() => {
    cleanupTimer.current = window.setInterval(cleanup, cleanupInterval)
    
    return () => {
      if (cleanupTimer.current) {
        clearInterval(cleanupTimer.current)
      }
    }
  }, [cleanup, cleanupInterval])

  const get = useCallback((key: string): T | null => {
    const entry = cache.current.get(key)
    
    if (!entry) return null
    
    const now = Date.now()
    if (now - entry.timestamp > entry.ttl) {
      cache.current.delete(key)
      return null
    }
    
    // Update access statistics
    entry.accessCount++
    entry.lastAccessed = now
    
    return entry.data
  }, [])

  const set = useCallback((key: string, data: T, ttl = defaultTTL) => {
    const now = Date.now()
    cache.current.set(key, {
      data,
      timestamp: now,
      ttl,
      accessCount: 0,
      lastAccessed: now
    })

    // Trigger cleanup if cache is getting too large
    if (cache.current.size > maxSize * 1.2) {
      cleanup()
    }
  }, [defaultTTL, maxSize, cleanup])

  const clear = useCallback((key?: string) => {
    if (key) {
      cache.current.delete(key)
    } else {
      cache.current.clear()
    }
  }, [])

  const has = useCallback((key: string): boolean => {
    const entry = cache.current.get(key)
    if (!entry) return false
    
    const now = Date.now()
    if (now - entry.timestamp > entry.ttl) {
      cache.current.delete(key)
      return false
    }
    
    return true
  }, [])

  const getStats = useCallback(() => {
    const entries = Array.from(cache.current.values())
    const now = Date.now()
    const validEntries = entries.filter(entry => now - entry.timestamp <= entry.ttl)
    
    return {
      size: cache.current.size,
      validSize: validEntries.length,
      maxSize,
      hitRate: validEntries.length > 0 
        ? validEntries.reduce((sum, entry) => sum + entry.accessCount, 0) / validEntries.length 
        : 0,
      oldestEntry: validEntries.length > 0 
        ? Math.min(...validEntries.map(entry => entry.timestamp))
        : null,
      newestEntry: validEntries.length > 0 
        ? Math.max(...validEntries.map(entry => entry.timestamp))
        : null
    }
  }, [maxSize])

  const invalidatePattern = useCallback((pattern: RegExp) => {
    const keysToDelete: string[] = []
    
    cache.current.forEach((_, key) => {
      if (pattern.test(key)) {
        keysToDelete.push(key)
      }
    })
    
    keysToDelete.forEach(key => cache.current.delete(key))
    return keysToDelete.length
  }, [])

  return { 
    get, 
    set, 
    clear, 
    has, 
    getStats, 
    invalidatePattern,
    cleanup: () => cleanup()
  }
}
